/***********************************************************
 *  File_Name  : XJEvent.h
 *  File_Path   :
 *  File_Encode : UTF8
 *  Description : 事件
 *
 *  OS : Linux, UNIX, Windows
 *  LastVersion  : 20150918
 *
 *  Author      : LiXiujie(李秀杰)
 *  Date        : 2015-9-18
 *  Version     : 20150918
 *  Description :
 *
 *  Edit Author :
 *  Edit Date   :
 *  Version     :
 *  Description :
 *
 ***********************************************************/

#ifndef SRC_XJEVENT_H_
#define SRC_XJEVENT_H_

#include "XJEnv.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <pthread.h>
#include <sys/time.h>
#include <sys/errno.h>
#endif
#include <iostream>
namespace XJUtilClass {

#ifdef _WIN32
class XJEvent {
public:
	/* bManualReset 创建的Event是自动复位还是人工复位     ,如果true,人工复位,
    一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复
    为无信号.     如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,
    该Event就会自动复位,变成无信号.
	 * bInitialState 初始状态,true,有信号,false无信号
	 * pszName Event对象名
	 * */
	XJEvent(BOOL bManualReset = FALSE, BOOL bInitialState = FALSE, LPCTSTR pszName = NULL, LPSECURITY_ATTRIBUTES pSecurity = NULL)
	{
		m_hEvent = ::CreateEvent(pSecurity, bManualReset, bInitialState, pszName);
		ASSERT(IsValid());
	}

	~XJEvent()
	{
		if(IsValid())
			VERIFY(::CloseHandle(m_hEvent));
	}

	BOOL Open(DWORD dwAccess, BOOL bInheritHandle, LPCTSTR pszName)
	{
		if(IsValid())
			VERIFY(::CloseHandle(m_hEvent));

		m_hEvent = ::OpenEvent(dwAccess, bInheritHandle, pszName);
		return(IsValid());
	}
	BOOL Wait(){
		DWORD ret = WaitForSingleObject(m_hEvent, INFINITE);
		if (ret == WAIT_OBJECT_0)
		{
			return TRUE;
		}
		return FALSE;
	}
	/* wait event success return 0
	 * timeout return 1
	 * error return -1
	 * */
	int TimedWait(long milliseconds){
		DWORD ret = WaitForSingleObject(m_hEvent, milliseconds);
		if (ret == WAIT_OBJECT_0)
		{
			return 0;
		}
		if (ret == WAIT_TIMEOUT)
		{
			return 1;
		}
		return -1;
	}
	/* PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event
对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.
对自动复位的Event对象,它仅释放第一个等到该事件的thread（如果有),而对于
人工复位的Event对象,它释放所有等待的thread.  */
	BOOL Pulse()	{return(::PulseEvent(m_hEvent));}
	BOOL Reset()	{return(::ResetEvent(m_hEvent));}
	BOOL Set()		{return(::SetEvent(m_hEvent));}

	HANDLE& GetHandle	() 	{return m_hEvent;}
	operator HANDLE		()	{return m_hEvent;}
	BOOL IsValid		()	{return m_hEvent != NULL;}

private:
	XJEvent(const XJEvent&);
	XJEvent operator = (const XJEvent&);

private:
	HANDLE m_hEvent;
};
#else
typedef struct
{
	bool pulse; // 脉冲模式，单步走
	unsigned long nWaitCount;  // 等待计数
    bool state;
    bool manual_reset;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}xj_event_t;
typedef xj_event_t *xj_p_event_t;
class XJEvent {
public:
	/* bManualReset 创建的Event是自动复位还是人工复位     ,如果true,人工复位,
    一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复
    为无信号.     如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,
    该Event就会自动复位,变成无信号.
	 * bInitialState 初始状态,true,有信号,false无信号
	 * */
	XJEvent(bool bManualReset = false, bool bInitialState = false)
	{
		m_hEvent  = new(std::nothrow) xj_event_t;
		if (m_hEvent){
			m_hEvent->state = bInitialState;
			m_hEvent->pulse = false;
			m_hEvent->nWaitCount = 0;
			m_hEvent->manual_reset = bManualReset;
		}
	    if (m_hEvent && pthread_mutex_init(&m_hEvent->mutex, NULL))
	    {
	        delete m_hEvent;
	        m_hEvent = NULL;
	    }
	    if (m_hEvent && pthread_cond_init(&m_hEvent->cond, NULL))
	    {
	        pthread_mutex_destroy(&m_hEvent->mutex);
	        delete m_hEvent;
	        m_hEvent = NULL;
	    }
	}

	~XJEvent()
	{
		if (m_hEvent){
			pthread_cond_destroy(&m_hEvent->cond);
			pthread_mutex_destroy(&m_hEvent->mutex);
			delete m_hEvent;
		}
	}
	bool Open(bool bManualReset = false, bool bInitialState = false){
		if (m_hEvent){
			pthread_cond_destroy(&m_hEvent->cond);
			pthread_mutex_destroy(&m_hEvent->mutex);
			delete m_hEvent;
		}
		m_hEvent  = new(std::nothrow) xj_event_t;
		if (m_hEvent){
			m_hEvent->state = bInitialState;
			m_hEvent->pulse = false;
			m_hEvent->nWaitCount = 0;
			m_hEvent->manual_reset = bManualReset;
		}
		if (m_hEvent && pthread_mutex_init(&m_hEvent->mutex, NULL))
		{
			delete m_hEvent;
			m_hEvent = NULL;
		}
		if (m_hEvent && pthread_cond_init(&m_hEvent->cond, NULL))
		{
			pthread_mutex_destroy(&m_hEvent->mutex);
			delete m_hEvent;
			m_hEvent = NULL;
		}
		return IsValid();
	}
	// 来等待其变为有信号
	bool Wait(){
		if (m_hEvent == NULL){
			return false;
		}
		if (pthread_mutex_lock(&m_hEvent->mutex))
		{
			return false;
		}
		m_hEvent->nWaitCount++;
		while (!m_hEvent->state)
		{
			if (pthread_cond_wait(&m_hEvent->cond, &m_hEvent->mutex))
			{
				m_hEvent->nWaitCount--;
				pthread_mutex_unlock(&m_hEvent->mutex);
				return false;
			}

		}
		m_hEvent->nWaitCount--;
		if (!m_hEvent->manual_reset || m_hEvent->pulse)
		{
			m_hEvent->state = false;
			m_hEvent->pulse = false;
		}
		if (pthread_mutex_unlock(&m_hEvent->mutex))
		{
			return false;
		}
		return true;
	}
	/* 来等待其变为有信号
	 * wait event success return 0
	 * timeout return 1
	 * error return -1
	 * */
	int TimedWait(long milliseconds){
		if (m_hEvent == NULL){
			return -1;
		}
		int rc = 0;
		struct timespec abstime;
		struct timeval tv;
		gettimeofday(&tv, NULL);
		abstime.tv_sec  = tv.tv_sec + milliseconds / 1000;
		abstime.tv_nsec = tv.tv_usec*1000 + (milliseconds % 1000)*1000000;
		if (abstime.tv_nsec >= 1000000000)
		{
			abstime.tv_nsec -= 1000000000;
			abstime.tv_sec++;
		}

		if (pthread_mutex_lock(&m_hEvent->mutex) != 0)
		{
			return -1;
		}
		m_hEvent->nWaitCount++;
		while (!m_hEvent->state)
		{
			if (rc = pthread_cond_timedwait(&m_hEvent->cond, &m_hEvent->mutex, &abstime))
			{
				m_hEvent->nWaitCount--;
				if (rc == ETIMEDOUT) break;
				pthread_mutex_unlock(&m_hEvent->mutex);
				return -1;
			}
		}
		m_hEvent->nWaitCount--;
		if (rc == 0 && (!m_hEvent->manual_reset || m_hEvent->pulse)) // 如果是自动复位或脉冲单步模式
		{
			m_hEvent->state = false;
			m_hEvent->pulse = false;
		}
		if (pthread_mutex_unlock(&m_hEvent->mutex) != 0)
		{
			return -1;
		}
		if (rc == ETIMEDOUT)
		{
			//timeout return 1
			return 1;
		}
		//wait event success return 0
		return 0;
	}
	// 来设置它使其有信号
	bool Pulse()	{
		if (m_hEvent == NULL){
			return false;
		}
		if (pthread_mutex_lock(&m_hEvent->mutex) != 0)
		{
			return false;
		}
		if (m_hEvent->nWaitCount){
			m_hEvent->state = true;
			m_hEvent->pulse = true;
		}else{
			m_hEvent->state = false;
			m_hEvent->pulse = true;
		}
		if (m_hEvent->manual_reset)
		{   // 函数会将所有等待该条件变量的线程解锁而不是仅仅解锁一个线程
			if(pthread_cond_broadcast(&m_hEvent->cond))
			{
				return false;
			}
		}
		else
		{   // 仅解锁一个线程
			if(pthread_cond_signal(&m_hEvent->cond))
			{
				return false;
			}
		}

		if (pthread_mutex_unlock(&m_hEvent->mutex) != 0)
		{
			return false;
		}
		return true;
	}
	// 来使其无信号
	bool Reset()	{
		if (m_hEvent == NULL){
			return false;
		}
		if (pthread_mutex_lock(&m_hEvent->mutex) != 0)
		{
			return false;
		}

		m_hEvent->state = false;
		m_hEvent->pulse = false;
		if (pthread_mutex_unlock(&m_hEvent->mutex) != 0)
		{
			return false;
		}
		return true;
	}
	// 来设置它使其有信号
	bool Set()		{
		if (m_hEvent == NULL){
			return false;
		}
		if (pthread_mutex_lock(&m_hEvent->mutex) != 0)
		{
			return false;
		}
		m_hEvent->state = true;
		m_hEvent->pulse = false;
		if (m_hEvent->manual_reset)// 人工复位，一直有信号
		{   // 连续
			if(pthread_cond_broadcast(&m_hEvent->cond))
			{
				return false;
			}
		}
		else
		{   // 自动复位,有一个信号
			if(pthread_cond_signal(&m_hEvent->cond))
			{
				return false;
			}
		}
		if (pthread_mutex_unlock(&m_hEvent->mutex) != 0)
		{
			return false;
		}
		return true;
	}

	xj_p_event_t GetHandle	() 	{return m_hEvent;}
	operator xj_p_event_t()	{return m_hEvent;}
	bool IsValid		()	{return m_hEvent != NULL;}

private:
	XJEvent(const XJEvent&);
	XJEvent operator = (const XJEvent&);

private:
	xj_p_event_t m_hEvent;
};
#endif
} /* namespace XJUtilClass */

#endif /* SRC_XJEVENT_H_ */
